package navigatore;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import observer.Broker;

import org.jgrapht.Graph;
import org.jgrapht.graph.SimpleDirectedWeightedGraph;
import org.jgrapht.graph.Subgraph;
//import utility.MatrixMap;
import utility.MyDefaultWeightedEdge;
import utility.ParserXML;
import utility.Triple;
import utility.Auto;
import utility.Auto.typeAuto;
import behaviourNavigatore.GenerateRoute;
import behaviourNavigatore.ManageCrossroads;
import behaviourNavigatore.MyFSM;
import behaviourNavigatore.PutInTheStreet;
import behaviourNavigatore.RegistrationYellowPage;
import behaviourNavigatore.UpdateAutoPosition;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.SequentialBehaviour;

public class AgenteNavigatore  extends Agent {
	
	
	private static final long serialVersionUID = 1L;
	
	
	//strutture che ci indica per ogni strada il livello di traffico!
	//private HashMap<String, Double> indexTrafficStreet = new HashMap<String, Double>();
	
	private Broker broker;
	private boolean helped = false;
	private boolean helping = false;
	
	private HashMap<Integer, Auto> autos =  new HashMap<Integer, Auto>();
	
	private List<Auto> waitingCarsWithoutWays = new LinkedList<Auto>();
	private List<Auto> waitingCarsWithWays = new LinkedList<Auto>();
	
	private Set<Triple<Dimension, String, String>> incroci = new HashSet<Triple<Dimension, String, String>>();
	private Set<Triple<Dimension, String, String>> entryPoint = new HashSet<Triple<Dimension, String, String>>();
	private Set<Triple<Dimension, String, String>> bridgeSource = new HashSet<Triple<Dimension, String, String>>();
	private Set<Triple<Dimension, String, String>> bridgeTarget = new HashSet<Triple<Dimension, String, String>>();
	private List<Integer> listaNavigatoriAssociati = new ArrayList<Integer>();
	private List<Integer> listaNavigatoriAiutati = new ArrayList<Integer>();
	private List<Integer> listaNavigatoriAiutanti = new ArrayList<Integer>();
	private SimpleDirectedWeightedGraph<Triple<Dimension, String, String>, MyDefaultWeightedEdge> graph;
	private Subgraph<Triple<Dimension,String,String>, MyDefaultWeightedEdge, Graph<Triple<Dimension,String,String>,MyDefaultWeightedEdge>> subGraph;
	
	
	private boolean active;
	
	
	//stati GenartateRoute
	public static final int CONTINUE_TO_GENRATE_RUOTE = 0;
	public static final int GENROUTE_TO_PUTINSTREET = 1;
	public static final int FINALSTATE = 2;
	
	//stati UpdateAutoPosition
	public static final int CONTINUE_TO_UPDATE_AUTO_POSITION = 0;
	public static final int UPDATEPOSITION_TO_MANAGECROSSROAD = 1;
	public static final int UPDATEPOSITION_TO_GENERATEROUTE = 2;
	public static final int UPDATEPOSITION_TO_PUTINSTREET = 3;
	public static final int UPDATEPOSITION_TO_BAGARGINGSTREET = 4;
	
	//stati BARGAININGSTREE
	public static final int BARGAININGSTREET_TO_UPDATE_AUTO_POSITION = 0;
	public static final int BARGAININGSTREET_TO_GENERATEROUTE = 1;
	public static final int BARGAININGSTREET_TO_PUTINSTREET = 2;
	public static final int CONTINUE_TO_BARGAININGSTREET= 3;
	
	
	private int maxNumAutoNavigatore=0;
	
	
	public AgenteNavigatore(SimpleDirectedWeightedGraph<Triple<Dimension, String, String>, MyDefaultWeightedEdge> graph,
			Subgraph<Triple<Dimension,String,String>, MyDefaultWeightedEdge, Graph<Triple<Dimension,String,String>,MyDefaultWeightedEdge>> subGraph) {
		// TODO Auto-generated constructor stub
		this.graph =graph;
		this.subGraph = subGraph;
		
		
		Set<MyDefaultWeightedEdge> setStreet = this.getSubGraph().edgeSet();

		//mi calcolo il massimio numero di auto che un navigatre puo processare
		for (MyDefaultWeightedEdge street : setStreet) {
			maxNumAutoNavigatore+= street.getWeight();
		}
		
		
	}

	@Override
	protected void setup() {
		// TODO Auto-generated method stub
		super.setup();
	
		this.active = true;
		
		addBehaviour(new MyFSM());
		
		
	}
	
	
	public boolean isHelped() {
		return helped;
	}

	public void setHelped(boolean helped) {
		this.helped = helped;
	}

	public boolean isHelping() {
		return helping;
	}

	public void setHelping(boolean helping) {
		this.helping = helping;
	}

	public List<Integer> getListaNavigatoriAiutati() {
		return listaNavigatoriAiutati;
	}

	public void setListaNavigatoriAiutati(List<Integer> listaNavigatoriAiutati) {
		this.listaNavigatoriAiutati = listaNavigatoriAiutati;
	}

	public List<Integer> getListaNavigatoriAiutanti() {
		return listaNavigatoriAiutanti;
	}

	public void setListaNavigatoriAiutanti(List<Integer> listaNavigatoriAiutanti) {
		this.listaNavigatoriAiutanti = listaNavigatoriAiutanti;
	}

	public int getMaxNumAutoNavigatore() {
		return maxNumAutoNavigatore;
	}

	public void setMaxNumAutoNavigatore(int maxNumAutoNavigatore) {
		this.maxNumAutoNavigatore = maxNumAutoNavigatore;
	}

	public int getNumAutoNavigatore()
	{
		return autos.size();
	}
	
	
	public List<Integer> getListaNavigatoriAssociati() {
		return listaNavigatoriAssociati;
	}

	public void setListaNavigatoriAssociati(List<Integer> listaNavigatoriAssociati) {
		this.listaNavigatoriAssociati = listaNavigatoriAssociati;
	}

	public Broker getBroker() {
		return broker;
	}

	public void setBroker(Broker broker) {
		this.broker = broker;
	}
	
	
	public void statistics() {
		
		double sommaSpeed = 0;
		
		for (Integer id : autos.keySet()) {
			
			sommaSpeed+= autos.get(id).getCurrentSpeedMedia();
		}
		
		

		double velMediaFinished = broker.velocitaMediaAutoManaged();
		double velIdealeFinished = broker.velocitaMediaIdealeAutoManaged();
		
		double fo = (velMediaFinished/velIdealeFinished);
		
		double newFo = fo * sommaSpeed/autos.size();
		
		
		
	}
	
	public HashMap<Integer, Auto> getAutos() {
		return autos;
	}


	public void setAutos(HashMap<Integer, Auto> autos) {
		this.autos = autos;
	}

	public void addAuto(Auto e) {
		autos.put(e.getId(), e);
	}
	
	public Auto getAuto(Integer i)
	{
		return autos.get(i);
	}
	
	public void removeAuto(Integer i)
	{
		 autos.remove(i);
	}

	public Graph<Triple<Dimension, String, String>, MyDefaultWeightedEdge> getGraph() {
		return graph;
	}


	public void setGraph(SimpleDirectedWeightedGraph<Triple<Dimension, String, String>, MyDefaultWeightedEdge> graph) {
		this.graph = graph;
	}


	public Subgraph<Triple<Dimension, String, String>, MyDefaultWeightedEdge, Graph<Triple<Dimension, String, String>, MyDefaultWeightedEdge>> getSubGraph() {
		return subGraph;
	}

	public void setSubGraph(
			Subgraph<Triple<Dimension, String, String>, MyDefaultWeightedEdge, Graph<Triple<Dimension, String, String>, MyDefaultWeightedEdge>> subGraph) {
		this.subGraph = subGraph;
	}

	public Set<Triple<Dimension, String, String>> getEntryPoint() {
		return entryPoint;
	}

	public void setEntryPoint(Set<Triple<Dimension, String, String>> entryPoint) {
		this.entryPoint = entryPoint;
	}

	public Set<Triple<Dimension, String, String>> getBridgeTarget() {
		return bridgeTarget;
	}

	public void setBridgeTarget(Set<Triple<Dimension, String, String>> bridgeTarget) {
		this.bridgeTarget = bridgeTarget;
	}

	public Set<Triple<Dimension, String, String>> getBridgeSource() {
		return bridgeSource;
	}

	public void setBridgeSource(Set<Triple<Dimension, String, String>> bridgeSource) {
		this.bridgeSource = bridgeSource;
	}

	public Set<Triple<Dimension, String, String>> getIncroci() {
		return incroci;
	}

	public void setIncroci(Set<Triple<Dimension, String, String>> incroci) {
		this.incroci = incroci;
	}

	public List<Auto> getWaitingCarsWithoutWays() {
		return waitingCarsWithoutWays;
	}

	public void setWaitingCarsWithoutWays(List<Auto> waitingCarsWithoutWays) {
		this.waitingCarsWithoutWays = waitingCarsWithoutWays;
	}

	//aggiunge un auto nella lista di attesa se
	// l'auto parte da uno dei suoi entryPoint
	public void addWaitingCarsWithoutWays(Auto a){
		
		if(entryPoint.contains(a.getStart()))
			waitingCarsWithoutWays.add(a);
	}
	
	public List<Auto> getWaitingCarsWithWays() {
		return waitingCarsWithWays;
	}

	public void setWaitingCarsWithWays(List<Auto> waitingCarsWithWays) {
		this.waitingCarsWithWays = waitingCarsWithWays;
	}
	
	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}
	
	@Override
	protected void takeDown() {
		// TODO Auto-generated method stub
		super.takeDown();
	}

}
